1   /*                        __    __  __  __    __  ___
2    *                       \  \  /  /    \  \  /  /  __/
3    *                        \  \/  /  /\  \  \/  /  /
4    *                         \____/__/  \__\____/__/.ɪᴏ
5    * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
6    */
7   package io.vavr.collection;
8   
9   import io.vavr.Function2;
10  import io.vavr.Tuple2;
11  import org.assertj.core.api.Assertions;
12  import org.junit.Test;
13  
14  import java.util.List;
15  import java.util.Random;
16  import java.util.concurrent.ThreadLocalRandom;
17  import java.util.function.Function;
18  import java.util.function.Predicate;
19  
20  import static io.vavr.API.Tuple;
21  import static org.assertj.core.api.Assertions.assertThat;
22  
23  public class VectorPropertyTest {
24  
25      @Test
26      public void shouldCreateAndGet() {
27          for (int i = 0; i < 500; i++) {
28              final Seq<Integer> expected = Array.range(0, i);
29              final Vector<Integer> actual = Vector.ofAll(expected);
30              for (int j = 0; j < actual.size(); j++) {
31                  assertThat(expected.get(j)).isEqualTo(actual.get(j));
32              }
33  
34              assert (i == 0) || !actual.trie.type.type().isPrimitive();
35  
36              /* boolean */
37              final Seq<Boolean> expectedBoolean = expected.map(v -> v > 0);
38              final Vector<Boolean> actualBoolean = Vector.ofAll(ArrayType.<boolean[]> asPrimitives(boolean.class, expectedBoolean));
39              assert (i == 0) || (actualBoolean.trie.type.type() == boolean.class);
40              assertAreEqual(expectedBoolean, actualBoolean);
41              assertAreEqual(expectedBoolean.append(null), actualBoolean.append(null));
42  
43              /* byte */
44              final Seq<Byte> expectedByte = expected.map(Integer::byteValue);
45              final Vector<Byte> actualByte = Vector.ofAll(ArrayType.<byte[]> asPrimitives(byte.class, expectedByte));
46              assert (i == 0) || (actualByte.trie.type.type() == byte.class);
47              assertAreEqual(expectedByte, actualByte);
48              assertAreEqual(expectedByte.append(null), actualByte.append(null));
49  
50              /* char */
51              final Seq<Character> expectedChar = expected.map(v -> (char) v.intValue());
52              final Vector<Character> actualChar = Vector.ofAll(ArrayType.<char[]> asPrimitives(char.class, expectedChar));
53              assert (i == 0) || (actualChar.trie.type.type() == char.class);
54              assertAreEqual(expectedChar, actualChar);
55              assertAreEqual(expectedChar.append(null), actualChar.append(null));
56  
57              /* double */
58              final Seq<Double> expectedDouble = expected.map(Integer::doubleValue);
59              final Vector<Double> actualDouble = Vector.ofAll(ArrayType.<double[]> asPrimitives(double.class, expectedDouble));
60              assert (i == 0) || (actualDouble.trie.type.type() == double.class);
61              assertAreEqual(expectedDouble, actualDouble);
62              assertAreEqual(expectedDouble.append(null), actualDouble.append(null));
63  
64              /* float */
65              final Seq<Float> expectedFloat = expected.map(Integer::floatValue);
66              final Vector<Float> actualFloat = Vector.ofAll(ArrayType.<float[]> asPrimitives(float.class, expectedFloat));
67              assert (i == 0) || (actualFloat.trie.type.type() == float.class);
68              assertAreEqual(expectedFloat, actualFloat);
69              assertAreEqual(expectedFloat.append(null), actualFloat.append(null));
70  
71              /* int */
72              final Vector<Integer> actualInt = Vector.ofAll(ArrayType.<int[]> asPrimitives(int.class, expected));
73              assert (i == 0) || (actualInt.trie.type.type() == int.class);
74              assertAreEqual(expected, actualInt);
75              assertAreEqual(expected.append(null), actual.append(null));
76  
77              /* long */
78              final Seq<Long> expectedLong = expected.map(Integer::longValue);
79              final Vector<Long> actualLong = Vector.ofAll(ArrayType.<long[]> asPrimitives(long.class, expectedLong));
80              assert (i == 0) || (actualLong.trie.type.type() == long.class);
81              assertAreEqual(expectedLong, actualLong);
82              assertAreEqual(expectedLong.append(null), actualLong.append(null));
83  
84              /* short */
85              final Seq<Short> expectedShort = expected.map(Integer::shortValue);
86              final Vector<Short> actualShort = Vector.ofAll(ArrayType.<short[]> asPrimitives(short.class, expectedShort));
87              assert (i == 0) || (actualShort.trie.type.type() == short.class);
88              assertAreEqual(expectedShort, actualShort);
89              assertAreEqual(expectedShort.append(null), actualShort.append(null));
90          }
91      }
92  
93      @Test
94      public void shouldIterate() {
95          for (byte depth = 0; depth <= 2; depth++) {
96              for (int i = 0; i < 5000; i++) {
97                  final Seq<Integer> expected = Array.range(0, i);
98                  final Vector<Integer> actual = Vector.ofAll(expected);
99                  assertAreEqual(actual, expected);
100             }
101         }
102 
103         Seq<Integer> expected = Array.range(0, 1000);
104         Vector<Integer> actual = Vector.ofAll(ArrayType.<int[]> asPrimitives(int.class, expected));
105         for (int drop = 0; drop <= (BitMappedTrie.BRANCHING_FACTOR + 1); drop++) {
106             final Iterator<Integer> expectedIterator = expected.iterator();
107             actual.trie.<int[]> visit((index, leaf, start, end) -> {
108                 for (int i = start; i < end; i++) {
109                     assertThat(leaf[i]).isEqualTo(expectedIterator.next());
110                 }
111                 return -1;
112             });
113 
114             expected = expected.tail().init();
115             actual = actual.tail().init();
116         }
117     }
118 
119     @Test
120     public void shouldPrepend() {
121         Seq<Integer> expected = Array.empty();
122         Vector<Integer> actual = Vector.empty();
123 
124         for (int drop = 0; drop <= (BitMappedTrie.BRANCHING_FACTOR + 1); drop++) {
125             for (Integer value : Iterator.range(0, 1000)) {
126                 expected = expected.drop(drop);
127                 actual = assertAreEqual(actual, drop, Vector::drop, expected);
128 
129                 expected = expected.prepend(value);
130                 actual = assertAreEqual(actual, value, Vector::prepend, expected);
131             }
132         }
133     }
134 
135     @Test
136     public void shouldAppend() {
137         Seq<Integer> expected = Array.empty();
138         Vector<Integer> actual = Vector.empty();
139 
140         for (int drop = 0; drop <= (BitMappedTrie.BRANCHING_FACTOR + 1); drop++) {
141             for (Integer value : Iterator.range(0, 500)) {
142                 expected = expected.drop(drop);
143                 actual = assertAreEqual(actual, drop, Vector::drop, expected);
144 
145                 expected = expected.append(value);
146                 actual = assertAreEqual(actual, value, Vector::append, expected);
147             }
148         }
149     }
150 
151     @Test
152     public void shouldUpdate() {
153         final Function<Integer, Integer> mapper = i -> i + 1;
154 
155         for (byte depth = 0; depth <= 2; depth++) {
156             final int length = 10_000;
157 
158             for (int drop = 0; drop <= (BitMappedTrie.BRANCHING_FACTOR + 1); drop++) {
159                 Seq<Integer> expected = Array.range(0, length);
160                 Vector<Integer> actual = Vector.ofAll(expected);
161 
162                 expected = expected.drop(drop); // test the `trailing` drops and the internal tree offset
163                 actual = assertAreEqual(actual, drop, Vector::drop, expected);
164 
165                 for (int i = 0; i < actual.length(); i++) {
166                     final Integer newValue = mapper.apply(actual.get(i));
167                     actual = actual.update(i, newValue);
168                 }
169 
170                 assertAreEqual(actual, 0, (a, p) -> a, expected.map(mapper));
171             }
172         }
173     }
174 
175     @Test
176     public void shouldDrop() {
177         final Seq<Integer> expected = Array.range(0, 2_000);
178         final Vector<Integer> actual = Vector.ofAll(expected);
179 
180         Vector<Integer> actualSingleDrop = actual;
181         for (int i = 0; i <= expected.length(); i++) {
182             final Seq<Integer> expectedDrop = expected.drop(i);
183 
184             assertAreEqual(actual, i, Vector::drop, expectedDrop);
185             assertAreEqual(actualSingleDrop, null, (a, p) -> a, expectedDrop);
186 
187             actualSingleDrop = actualSingleDrop.drop(1);
188         }
189     }
190 
191     @Test
192     public void shouldDropRight() {
193         final Seq<Integer> expected = Array.range(0, 2_000);
194         final Vector<Integer> actual = Vector.ofAll(expected);
195 
196         Vector<Integer> actualSingleDrop = actual;
197         for (int i = 0; i <= expected.length(); i++) {
198             final Seq<Integer> expectedDrop = expected.dropRight(i);
199 
200             assertAreEqual(actual, i, Vector::dropRight, expectedDrop);
201             assertAreEqual(actualSingleDrop, null, (a, p) -> a, expectedDrop);
202 
203             actualSingleDrop = actualSingleDrop.dropRight(1);
204         }
205     }
206 
207     @Test
208     public void shouldSlice() {
209         for (int length = 1, end = 500; length <= end; length++) {
210             Seq<Integer> expected = Array.range(0, length);
211             Vector<Integer> actual = Vector.ofAll(expected);
212 
213             for (int i = 0; i <= expected.length(); i++) {
214                 expected = expected.slice(1, expected.size() - 1);
215                 actual = assertAreEqual(actual, i, (a, p) -> a.slice(1, a.size() - 1), expected);
216             }
217         }
218     }
219 
220     @Test
221     public void shouldBehaveLikeArray() {
222         final int seed = ThreadLocalRandom.current().nextInt();
223         System.out.println("using seed " + seed);
224         final Random random = new Random(seed);
225 
226         for (int i = 1; i < 10; i++) {
227             Seq<Object> expected = Array.empty();
228             Vector<Object> actual = Vector.empty();
229             for (int j = 0; j < 20_000; j++) {
230                 Seq<Tuple2<Seq<Object>, Vector<Object>>> history = Array.empty();
231 
232                 if (percent(random) < 20) {
233                     expected = Array.ofAll(Vector.ofAll(randomValues(random, 100)).filter(v -> v instanceof Integer));
234                     actual = (percent(random) < 30) ? Vector.narrow(Vector.ofAll(ArrayType.<int[]> asPrimitives(int.class, expected))) : Vector.ofAll(expected);
235                     assertAreEqual(expected, actual);
236                     history = history.append(Tuple(expected, actual));
237                 }
238 
239                 if (percent(random) < 50) {
240                     final Object value = randomValue(random);
241                     expected = expected.append(value);
242                     actual = assertAreEqual(actual, value, Vector::append, expected);
243                     history = history.append(Tuple(expected, actual));
244                 }
245                 if (percent(random) < 10) {
246                     Iterable<Object> values = randomValues(random, random.nextInt(2 * BitMappedTrie.BRANCHING_FACTOR));
247                     expected = expected.appendAll(values);
248 
249                     values = (percent(random) < 50) ? Iterator.ofAll(values.iterator()) : values;  /* not traversable again */
250                     actual = assertAreEqual(actual, values, Vector::appendAll, expected);
251                     history = history.append(Tuple(expected, actual));
252                 }
253 
254                 if (percent(random) < 50) {
255                     final Object value = randomValue(random);
256                     expected = expected.prepend(value);
257                     actual = assertAreEqual(actual, value, Vector::prepend, expected);
258                     history = history.append(Tuple(expected, actual));
259                 }
260                 if (percent(random) < 10) {
261                     Iterable<Object> values = randomValues(random, random.nextInt(2 * BitMappedTrie.BRANCHING_FACTOR));
262                     expected = expected.prependAll(values);
263 
264                     values = (percent(random) < 50) ? Iterator.ofAll(values) : values;  /* not traversable again */
265                     actual = assertAreEqual(actual, values, Vector::prependAll, expected);
266                     history = history.append(Tuple(expected, actual));
267                 }
268 
269                 if (percent(random) < 30) {
270                     final int n = random.nextInt(expected.size() + 1);
271                     expected = expected.drop(n);
272                     actual = assertAreEqual(actual, n, Vector::drop, expected);
273                     history = history.append(Tuple(expected, actual));
274                 }
275 
276                 if (percent(random) < 10) {
277                     final int index = random.nextInt(expected.size() + 1);
278                     Iterable<Object> values = randomValues(random, random.nextInt(2 * BitMappedTrie.BRANCHING_FACTOR));
279                     expected = expected.insertAll(index, values);
280 
281                     values = (percent(random) < 50) ? Iterator.ofAll(values) : values;  /* not traversable again */
282                     actual = assertAreEqual(actual, values, (a, p) -> a.insertAll(index, p), expected);
283                     history = history.append(Tuple(expected, actual));
284                 }
285 
286                 if (percent(random) < 30) {
287                     final int n = random.nextInt(expected.size() + 1);
288                     expected = expected.take(n);
289                     actual = assertAreEqual(actual, n, Vector::take, expected);
290                     history = history.append(Tuple(expected, actual));
291                 }
292 
293                 if (!expected.isEmpty()) {
294                     assertThat(actual.head()).isEqualTo(expected.head());
295                     Assertions.assertThat(actual.tail().toJavaList()).isEqualTo(expected.tail().toJavaList());
296                     history = history.append(Tuple(expected, actual));
297                 }
298 
299                 if (!expected.isEmpty()) {
300                     final int index = random.nextInt(expected.size());
301                     assertThat(actual.get(index)).isEqualTo(expected.get(index));
302                     history = history.append(Tuple(expected, actual));
303                 }
304 
305                 if (percent(random) < 50) {
306                     if (!expected.isEmpty()) {
307                         final int index = random.nextInt(expected.size());
308                         final Object value = randomValue(random);
309                         expected = expected.update(index, value);
310                         actual = assertAreEqual(actual, null, (a, p) -> a.update(index, value), expected);
311                         history = history.append(Tuple(expected, actual));
312                     }
313                 }
314 
315                 if (percent(random) < 20) {
316                     final Function<Object, Object> mapper = val -> (val instanceof Integer) ? ((Integer) val + 1) : val;
317                     expected = expected.map(mapper);
318                     actual = assertAreEqual(actual, null, (a, p) -> a.map(mapper), expected);
319                     history = history.append(Tuple(expected, actual));
320                 }
321 
322                 if (percent(random) < 30) {
323                     final Predicate<Object> filter = val -> (String.valueOf(val).length() % 10) == 0;
324                     expected = expected.filter(filter);
325                     actual = assertAreEqual(actual, null, (a, p) -> a.filter(filter), expected);
326                     history = history.append(Tuple(expected, actual));
327                 }
328 
329                 if (percent(random) < 30) {
330                     for (int k = 0; k < 2; k++) {
331                         if (!expected.isEmpty()) {
332                             final int to = random.nextInt(expected.size());
333                             final int from = random.nextInt(to + 1);
334                             expected = expected.slice(from, to);
335                             actual = assertAreEqual(actual, null, (a, p) -> a.slice(from, to), expected);
336                             history = history.append(Tuple(expected, actual));
337                         }
338                     }
339                 }
340 
341                 history.forEach(t -> assertAreEqual(t._1, t._2)); // test that the modifications are persistent
342             }
343         }
344     }
345 
346     private int percent(Random random) { return random.nextInt(101); }
347     private Iterable<Object> randomValues(Random random, int count) {
348         final Vector<Object> values = Vector.range(0, count).map(v -> randomValue(random));
349         final int percent = percent(random);
350         if (percent < 30) {
351             return values.toJavaList();  /* not Traversable */
352         } else {
353             return values;
354         }
355     }
356     private Object randomValue(Random random) {
357         final int percent = percent(random);
358         if (percent < 5) {
359             return null;
360         } else if (percent < 10) {
361             return "String";
362         } else {
363             return random.nextInt();
364         }
365     }
366 
367     private static <T extends Seq<?>, P> T assertAreEqual(T previousActual, P param, Function2<T, P, T> actualProvider, Seq<?> expected) {
368         final T actual = actualProvider.apply(previousActual, param);
369         assertAreEqual(expected, actual);
370         return actual; // makes debugging a lot easier, as the frame can be dropped and rerun on AssertError
371     }
372 
373     private static void assertAreEqual(Seq<?> expected, Seq<?> actual) {
374         final List<?> actualList = actual.toJavaList();
375         final List<?> expectedList = expected.toJavaList();
376         assertThat(actualList).isEqualTo(expectedList); // a lot faster than `hasSameElementsAs`
377     }
378 }